const std = @import("std");
const os = @import("os.zig");
const print = os.debug.print;

var first: std.atomic.Value(bool) = .init(true);
var started: std.atomic.Value(bool) = .init(false);

// start() jumps here in supervisor mode on all CPUs.
pub fn main() callconv(.c) noreturn {
    const id = os.proc.Cpu.id();
    if (first.cmpxchgStrong(true, false, .acq_rel, .monotonic) == null) {
        os.arch.qemu.init(); // early init

        print(
            \\
            \\xv6/{t} is booting
            \\
            \\
        , .{os.builtin.cpu.arch});

        os.mem.init(); // create kernel page table
        os.proc.init(); // process table
        os.fdt.probe(); // map device memory regions

        const driver_init = os.proc.kthreadd.spawn("driver init", .{ .func = &os.driver.init });
        const fs_init = os.proc.kthreadd.spawn("fs init", .{ .func = &os.fs.init });
        fs_init.adopt(driver_init); // fs waits for virtio-blk initialization

        const start_proc = os.proc.kthreadd.spawn("start", .{ .func = &os.proc.start });
        start_proc.adopt(fs_init); // init proc waits for fs initialization

        started.store(true, .release);
    } else {
        while (!started.load(.acquire)) {}
        print("hart {} starting\n", .{id});
    }

    os.mem.inithart(); // turn on paging
    os.trap.inithart(); // install kernel trap vector
    os.driver.plic.inithart(id); // ask PLIC for device interrupts

    os.proc.scheduler(); // start process scheduling
}
